package com.codebattery.service;


import com.codebattery.client.GoodsFeignClient;
import com.codebattery.client.MallFeignClient;
import com.codebattery.client.StorageFeignClient;
import com.codebattery.client.UserFeignClient;
import com.codebattery.domain.entity.Order;
import com.codebattery.domain.entity.OrderItem;
import com.codebattery.domain.model.*;
import com.codebattery.domain.param.CartOrderInfo;
import com.codebattery.mapper.BaseMapper;
import com.codebattery.repository.OrderMapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.core.strategy.keygen.SnowflakeShardingKeyGenerator;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;


@Service
@Slf4j
public class OrderService extends MyBatisBaseServiceImpl<Order, Long> {

    @Resource
    private OrderMapper orderMapper;
    @Resource
    private StorageFeignClient storageFeignClient;
    @Resource
    private UserFeignClient userFeignClient;
    @Resource
    private MallFeignClient mallFeignClient;
    @Resource
    private OrderItemService orderItemService;
    @Resource
    private GoodsFeignClient goodsFeignClient;

    @Override
    protected BaseMapper<Order, Long> mapper() {
        return orderMapper;
    }

    //    @Async
    @GlobalTransactional(rollbackFor = Exception.class, timeoutMills = 100000)
    public Order createOrderFromCart(CartOrderInfo cartOrderInfo) throws Exception {
        final SnowflakeShardingKeyGenerator keyGenerator = new SnowflakeShardingKeyGenerator();
        AtomicReference<Order> order = new AtomicReference<>();
        Map<String, String> query = new HashMap<>();
        query.put("userId", Optional.of(cartOrderInfo.getUserId()).get().toString());
        CartInfo cart = mallFeignClient.getCart(query);
        Optional.ofNullable(cart)
                .ifPresent(cartInfo -> {

                    MemberInfo memberInfo = userFeignClient.getMember(Long.valueOf(cartOrderInfo.getUserId()));
                    ReceiveAddressInfo addressInfo = userFeignClient.getReceiveAddress(Long.valueOf(cartOrderInfo.getReceiveId()));

                    Order o = new Order(
                            new Long(keyGenerator.generateKey().toString()),
                            Long.valueOf(Optional.ofNullable(cartOrderInfo.getUserId()).orElse(0)),
                            null,
                            new Date(),
                            memberInfo.getUsername(),
                            cartInfo.getPrice(),
                            null,
                            new BigDecimal(0.00),
                            new BigDecimal(0.00),
                            new BigDecimal(0.00),
                            new BigDecimal(0.00),
                            new BigDecimal(0.00),
                            null,
                            null,
                            0,
                            null,
                            null,
                            null,
                            null,
                            0,
                            0,
                            null,
                            null,
                            null,
                            null,
                            null,
                            null,
                            addressInfo.getName(),
                            addressInfo.getPhoneNumber(),
                            addressInfo.getPostCode(),
                            addressInfo.getProvince(),
                            addressInfo.getCity(),
                            addressInfo.getRegion(),
                            addressInfo.getDetailAddress(),
                            cartOrderInfo.getNote(),
                            0,
                            0,
                            null,
                            null,
                            null,
                            null,
                            null,
                            null,
                            new Date()
                    );
                    this.insert(o);

                    Optional.ofNullable(cartOrderInfo.getCartItems()).ifPresent(cartItems -> {
                        cartItems.stream().forEach(cartItem -> {

                            Goods goods = goodsFeignClient.getGoods(cartItem.getGoodsId());

                            OrderItem item = new OrderItem(
                                    null,
                                    Long.valueOf(cartOrderInfo.getUserId()),
                                    o.getOrderId(),
                                    new Long(cartItem.getGoodsId()),
                                    cartItem.getImg(),
                                    goods.getName(),
                                    null,
                                    null,
                                    new BigDecimal(cartItem.getPrice()),
                                    cartItem.getCount(),
                                    null,
                                    null,
                                    null,
                                    cartItem.getCount(),
                                    goods.getShop().getId(),
                                    goods.getShop().getName(),
                                    null,
                                    null,
                                    null,
                                    null,
                                    null,
                                    null,
                                    null,
                                    null,
                                    null,
                                    null,
                                    cartItem.getMeal(),
                                    null,
                                    0,
                                    null,
                                    null,
                                    0,
                                    0,
                                    new Date(),
                                    new Date()
                            );

                            int insert = orderItemService.insert(item);

                            log.debug(String.valueOf(insert));
                        });
                    });

                    order.set(o);

                    /*
                     * 清空购物车
                     */
                    mallFeignClient.emptyCart(cartOrderInfo.getUserId().toString());
                });


        return order.get();
//        return CompletableFuture.completedFuture(order.get());
    }

    @Async
    @GlobalTransactional(rollbackFor = Exception.class, timeoutMills = 100000)
    public CompletableFuture<Order> create(Order order) throws Exception {
        Order o = null;

//        o = orderRepository.save(order);
        this.insert(order);

        return CompletableFuture.completedFuture(o);
    }

//    @Async
//    public CompletableFuture<List<Order>> getAllOrders() {
//
//        List<Order> orders = this.selectAll();
//
//        return CompletableFuture.completedFuture(orders);
//    }

    /**
     * 分页获取用户的订单信息
     *
     * @param memberId
     * @return
     */
    public PageInfo<MemeberOrderInfo> getMemberOrders(String memberId) {

        PageHelper.startPage(1, 10);
        List<MemeberOrderInfo> memberOrders = this.orderMapper.getMemberOrders(memberId);

        /*
         * 合并一个订单的商家信息
         */
        Optional.ofNullable(memberOrders).ifPresent(orders -> {

            orders.stream().forEach(order -> {
                Map<Integer, String> shops = new HashMap<>();
                List<MemeberOrderInfo.ShopInfo> shopInfos = new ArrayList<>();
                Optional.ofNullable(order.getDetailInfos()).ifPresent(detailInfo -> {
                    detailInfo.stream().forEach(item -> {
                        shops.put(item.getShopId(), item.getShopName());
                    });
                });

                shops.forEach((k, v) -> {
                    MemeberOrderInfo.ShopInfo shopInfo = new MemeberOrderInfo.ShopInfo();
                    shopInfo.setShopId(k);
                    shopInfo.setShopName(v);
                    shopInfos.add(shopInfo);
                });
                order.setShopInfos(shopInfos);
            });

        });

        PageInfo<MemeberOrderInfo> pageInfo = new PageInfo<>(memberOrders);

        return pageInfo;
    }

}
